#include <stdio.h>
#include <string.h>
#include <ulog/ulog.h>
#include "iic_function.h"
#include "aos/hal/i2c.h"
#include "camera_config.h"
#include "drv_isp.h"
#include "soc.h"
#include "pin_name.h"
#include "gc1054_drv.h"
#include "gc1054_config.h"
#include "drv_gpio.h"
#include <aos/kernel.h>
#include "cli_api.h"

static i2c_dev_t i2c_gc1054;
static i2c_dev_t i2c_gc1054_right;

extern gpio_pin_handle_t gpio_pin_handle;

int gc1054_debug_test(void);

struct gc1054_regval_list {
    uint8_t addr;
    uint8_t data;
};


struct gc1054_regval_list GC1054_raw[]=
{
    /* {Address                 , DefaultValue                       , pName                 , Flags } */
	
	///Htotal=1726    linetotal=750   row_time=44.26us///
	/////////////////////////////////////////////////////
	//////////////////////   SYS   //////////////////////
	/////////////////////////////////////////////////////
	{0xf2 , 0x00},
	{0xf6 , 0x00},
	{0xfc , 0x04},
	{0xf7 , 0x01},
	{0xf8 , 0x0c},
	{0xf9 , 0x06},
	{0xfa , 0x80},
	{0xfc , 0x0e},
	/////////////////////////////////////////////////
	////////////   ANALOG & CISCTL   ////////////////
	/////////////////////////////////////////////////
	{0xfe , 0x00},
	{0x03 , 0x01}, 	//exp_line_h // 750/2 = 375 lines
	{0x04 , 0x77}, 	//exp_line_l
	{0x05 , 0x02}, //HB
	{0x06 , 0x07},
	{0x07 , 0x00}, //VB
	{0x08 , 0x0a}, 
	{0x09 , 0x00},
	{0x0a , 0x04}, //row start
	{0x0b , 0x00},
	{0x0c , 0x00}, //col start
	{0x0d , 0x02}, 
	{0x0e , 0xd4}, //height 724
	{0x0f , 0x05}, 
	{0x10 , 0x08}, //width 1288
	{0x17 , 0xc3}, //flip mirror
	{0x18 , 0x02},
	{0x19 , 0x08},
	{0x1a , 0x18},
	{0x1e , 0x50},
	{0x1f , 0x80},
	{0x21 , 0x30},
	{0x23 , 0xf8},
	{0x25 , 0x10},
	{0x28 , 0x20},
	{0x34 , 0x08}, //data low
	{0x3c , 0x10},
	{0x3d , 0x0e},
	{0xcc , 0x8e},
	{0xcd , 0x9a},
	{0xcf , 0x70},
	{0xd0 , 0xa9},
	{0xd1 , 0xc5},
	{0xd2 , 0xed}, //data high
	{0xd8 , 0x3c}, //dacin offset
	{0xd9 , 0x7a},
	{0xda , 0x12},
	{0xdb , 0x50},
	{0xde , 0x0c},
	{0xe3 , 0x60},
	{0xe4 , 0x78},
	{0xfe , 0x01},
	{0xe3 , 0x01},
	{0xe6 , 0x10}, //ramps offset
	////////////////////////////////////////////////
	/////////////////   ISP   //////////////////////
	////////////////////////////////////////////////
	{0xfe , 0x01},
	{0x80 , 0x50},
	{0x88 , 0x73},
	{0x89 , 0x03},
	{0x90 , 0x01}, 
	{0x92 , 0x02}, //crop win 2<=y<=4
	{0x94 , 0x03}, //crop win 2<=x<=5
	{0x95 , 0x02}, //crop win height
	{0x96 , 0xd0},
	{0x97 , 0x05}, //crop win width
	{0x98 , 0x00},
	/////////////////////////////////////////////////
	//////////////////   BLK   //////////////////////
	/////////////////////////////////////////////////
	{0xfe , 0x01},
	{0x40 , 0x22},
	{0x43 , 0x03},
	{0x4e , 0x3c},
	{0x4f , 0x00},
	{0x60 , 0x00},
	{0x61 , 0x80},
	/////////////////////////////////////////////////
	//////////////////   GAIN   /////////////////////
	/////////////////////////////////////////////////
	{0xfe , 0x01},
	{0xb0 , 0x48},
	{0xb1 , 0x01}, //dgain_i = 1x
	{0xb2 , 0x00}, //dgain_d = +0
	{0xb6 , 0x00}, //again   = 1x
	{0xfe , 0x02},
	{0x01 , 0x00},
	{0x02 , 0x01},
	{0x03 , 0x02},
	{0x04 , 0x03},
	{0x05 , 0x04},
	{0x06 , 0x05},
	{0x07 , 0x06},
	{0x08 , 0x0e},
	{0x09 , 0x16},
	{0x0a , 0x1e},
	{0x0b , 0x36},
	{0x0c , 0x3e},
	{0x0d , 0x56},
	{0xfe , 0x02},
	{0xb0 , 0x00}, //col_gain[11:8]
	{0xb1 , 0x00},
	{0xb2 , 0x00},
	{0xb3 , 0x11},
	{0xb4 , 0x22},
	{0xb5 , 0x54},
	{0xb6 , 0xb8},
	{0xb7 , 0x60},
	{0xb9 , 0x00}, //col_gain[12]
	{0xba , 0xc0},
	{0xc0 , 0x20}, //col_gain[7:0]
	{0xc1 , 0x2d},
	{0xc2 , 0x40},
	{0xc3 , 0x5b},
	{0xc4 , 0x80},
	{0xc5 , 0xb5},
	{0xc6 , 0x00},
	{0xc7 , 0x6a},
	{0xc8 , 0x00},
	{0xc9 , 0xd4},
	{0xca , 0x00},
	{0xcb , 0xa8},
	{0xcc , 0x00},
	{0xcd , 0x50},
	{0xce , 0x00},
	{0xcf , 0xa1},
	////////////////////////////////////////////////
	///////////////   DARKSUN   ////////////////////
	////////////////////////////////////////////////
	{0xfe , 0x02},
	{0x54 , 0xf7},
	{0x55 , 0xf0},
	{0x56 , 0x00},
	{0x57 , 0x00},
	{0x58 , 0x00},
	{0x5a , 0x04},
	///////////////////////////////////////////////
	/////////////////   DD   //////////////////////
	///////////////////////////////////////////////
	{0xfe , 0x04},
	{0x81 , 0x8a},
	////////////////////////////////////////////////
	/////////////////	 MIPI	/////////////////////
	////////////////////////////////////////////////
	{0xfe , 0x03},
	{0x01 , 0x03},
	{0x02 , 0x11},
	{0x03 , 0x90},
	{0x10 , 0x90},
	{0x11 , 0x2b},
	{0x12 , 0x40}, //lwc 1280*5/4
	{0x13 , 0x06},
	{0x15 , 0x06},
	{0x21 , 0x02},
	{0x22 , 0x02},
	{0x23 , 0x08},
	{0x24 , 0x02},
	{0x25 , 0x10},
	{0x26 , 0x04},
	{0x29 , 0x02},
	{0x2a , 0x02},
	{0x2b , 0x04},
	{0xfe , 0x00},
	
};

struct gc1054_regval_list GC1054_standby[]=
{
	{0xfe , 0x03},
	{0x10 , 0x00},
	{0xfe , 0x00},
//	{0xf7 , 0x00},
//	{0xfc , 0x01},
//	{0xf9 , 0x01},
};

struct gc1054_regval_list GC1054_stream[]=
{	
//	{0xf9 , 0x06},
//	{0xf7 , 0x01},
//	{0xfc , 0x0e},
	{0xfe , 0x03},
	{0x10 , 0x90},
	{0xfe , 0x00},
};

static int gc1054_check_id(i2c_dev_t *i2c)
{
    int ret = 0;
    uint8_t data = 0;

    printf("check gc1054 id: \n");
    
    ret = iic_read_r8_d8(i2c,  GC1054_REG_CHIPID_H, &data);
    printf("H %02x \n",data);
    if (ret < 0 || data != 0x10)
        return -1;
    ret = iic_read_r8_d8(i2c, GC1054_REG_CHIPID_L, &data);
    printf("L %02x \n",data);
   	if (ret < 0 || data != 0x54)
        return -1;

    return ret;
}

int gc1054_hw_reset(pin_name_e rst_n)
{
	//Config USI3_SCLK <=> GPIOB12  
    gpio_pin_handle = csi_gpio_pin_initialize(rst_n, 0);
	
    csi_gpio_pin_config_mode(gpio_pin_handle, GPIO_MODE_PULLDOWN);
    csi_gpio_pin_config_direction(gpio_pin_handle, GPIO_DIRECTION_OUTPUT);
    csi_gpio_pin_write(gpio_pin_handle, 0);
	
	aos_msleep(500);
    csi_gpio_pin_write(gpio_pin_handle, 1);
    return 0;
}



int gc1054_init(i2c_dev_t *i2c, uint32_t dev_addr)
{
   	memcpy(&i2c_gc1054, i2c, sizeof(i2c_dev_t));
    i2c_gc1054.config.dev_addr = dev_addr;
    //Check the id of camera
   	int ret = gc1054_check_id(&i2c_gc1054);
    if (ret < 0) {
        printf("gc1054 check id fail\n");
        return ret;
    }
    return ret;
}

int gc1054_right_init(i2c_dev_t *i2c, uint32_t dev_addr)
{
   	memcpy(&i2c_gc1054_right, i2c, sizeof(i2c_dev_t));
    i2c_gc1054_right.config.dev_addr = dev_addr;
    //Check the id of camera
   	int ret = gc1054_check_id(&i2c_gc1054_right);
    if (ret < 0) {
        printf("gc1054 check id fail\n");
        return ret;
    }
    return ret;
}

int32_t gc1054_config(imageFormat_t cfg)
{
	int32_t ret = 0;

	if( R_720P == cfg.res && RAW10 == cfg.format)
	{
		ret = iic_write_array_r8_d8(&i2c_gc1054, (regval_list *)gc1054_1280x720_raw10, ARRAY_SIZE(gc1054_1280x720_raw10));
		if (ret < 0) {
			return -1;
		}
#if 0
		uint32_t num = 0;
		uint32_t size = ARRAY_SIZE(gc1054_1280x720_raw10);
		uint32_t reg_dat = 0;
		while(num < size)
		{
			iic_read_r8_d8(&i2c_gc1054, gc1054_1280x720_raw10[num].addr, &reg_dat);
			printf("gc1054 addr = 0x%02x, data = 0x%02x, \n", gc1054_1280x720_raw10[num].addr, reg_dat);
			num++;
		}
#endif
		
		printf("gc1054 reg init done. \n");
	}

	return ret;
}


int32_t gc1054_right_config(imageFormat_t cfg)
{
	int32_t ret = 0;

	if( R_720P == cfg.res && RAW10 == cfg.format)
	{
		ret = iic_write_array_r8_d8(&i2c_gc1054_right, (regval_list *)gc1054_1280x720_raw10, ARRAY_SIZE(gc1054_1280x720_raw10));
		if (ret < 0) {
			return -1;
		}
#if 0
		uint32_t num = 0;
		uint32_t size = ARRAY_SIZE(gc1054_1280x720_raw10);
		uint32_t reg_dat = 0;
		while(num < size)
		{
			iic_read_r8_d8(&i2c_gc1054, gc1054_1280x720_raw10[num].addr, &reg_dat);
			printf("gc1054 addr = 0x%02x, data = 0x%02x, \n", gc1054_1280x720_raw10[num].addr, reg_dat);
			num++;
		}
#endif
		
		printf("gc1054 reg init done. \n");
	}

	return ret;
}

int gc1054_write(uint8_t reg, uint8_t value){

    int ret = 0;
    ret = iic_write_r8_d8(&i2c_gc1054, reg, value);

}

int gc1054_read(uint8_t reg){

    int ret = 0;
    uint8_t data[2] = {0};

    ret = iic_read_r8_d8(&i2c_gc1054,  reg, &data);

    printf("read reg 0x%02x value 0x%x \n", reg,data[0]);
}

int gc1054_reg_write(i2c_dev_t *i2c, uint32_t dev_addr, uint8_t reg, uint8_t value){

    int ret = 0;
    memcpy(&i2c_gc1054, i2c, sizeof(i2c_dev_t));
    i2c_gc1054.config.dev_addr = dev_addr;
    
    ret = iic_write_r8_d8(&i2c_gc1054, reg, value);

}

int gc1054_reg_read(i2c_dev_t *i2c, uint32_t dev_addr, uint8_t reg){

    int ret = 0;
    uint8_t data[2] = {0};

    memcpy(&i2c_gc1054, i2c, sizeof(i2c_dev_t));
    i2c_gc1054.config.dev_addr = dev_addr;

    ret = iic_read_r8_d8(&i2c_gc1054,  reg, &data);

}

int gc1054_mode_config(i2c_dev_t *i2c, uint32_t dev_addr, sensor_mode_t mode)
{
	int ret = 0;
	memcpy(&i2c_gc1054, i2c, sizeof(i2c_dev_t));
    i2c_gc1054.config.dev_addr = dev_addr;
	if(STANDBY == mode){
		//printf("standby mode!\n");
		for(int i = 0; i<ARRAY_SIZE(GC1054_standby); i++){
			iic_write_r8_d8(&i2c_gc1054, GC1054_standby[i].addr, GC1054_standby[i].data);
		}
	}else{
		//printf("stream mode!\n");
		for(int i = 0; i<ARRAY_SIZE(GC1054_stream); i++){
			iic_write_r8_d8(&i2c_gc1054, GC1054_stream[i].addr, GC1054_stream[i].data);
		}
	}
	return 0;
}

static void sensor_command(char *outbuf, int len, int argc, char **argv)
{
    uint8_t reg = 0;
    uint8_t value = 0;

    if (argc == 1) {
        printf("wrong argv numer.\n");
        return;
    }
    if (!strcmp(argv[1], "set")) {
        reg = strtoul(argv[2], NULL, 16);
        value = strtoul(argv[3], NULL, 16);
        printf("set reg 0x%x, value 0x%x ", reg, value);
        gc1054_write(reg, value);
        
    } 
    else if (!strcmp(argv[1], "get")) {
        
            reg = strtoul(argv[2], NULL, 16);
            
            printf("get reg 0x%x \n", reg);
            gc1054_read(reg);
        }	
    else if (!strcmp(argv[1], "get_all")) {
        	gc1054_debug_test();
        }
	else if (!strcmp(argv[1], "standby")) {
        	sensor_standby(1);
        }
	else if (!strcmp(argv[1], "stream")) {
        	sensor_stream(1);
        }
    else {
        cli_printf("param invalid!\n");
        return;
    }

    return;
}


int gc1054_debug_test(void)
{
    int32_t i = 0, ret;

    while(i < ARRAY_SIZE(GC1054_raw)) {
		gc1054_read(GC1054_raw[i].addr);
        i++;
    }

	return 0;
}


static const struct cli_command_st img_cli_cmd[] = 
{
    [0] =
    {
        .name            = "sensor",
        .help            = "sensor set/get register",
        .function        = sensor_command
    },

};


int gc1054_img_cli_register(void) 
{
    int ret = 0;

    ret = cli_register_commands(img_cli_cmd, sizeof(img_cli_cmd)/sizeof(struct cli_command_st));
    if (ret != 0) {
        return ret;
    }

    return 0;
}


